<?php
declare (strict_types=1);

namespace app\common\logic;

use app\common\logic\category\Category;
use app\common\model\Template as TemplateModel;
use app\course\logic\base\Course;
use app\course\logic\base\CourseSection;
use app\course\logic\base\CourseStudent;
use app\course\logic\classes\Classes;
use app\promotion\logic\Promotion;
use app\topic\logic\Topic;
use app\user\logic\teacher\Teacher;
use ArrayObject;
use think\App;
use think\Collection;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\Model;

/**
 * Class Template
 *
 * @package app\common\logic
 */
class Template extends TemplateModel
{

    /**
     * getTemplate
     * Author: 亓官雨树 <lucky.max@foxmail.com>
     * Date: 23/07/06
     *
     * @return array
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public function getTemplateData(): array
    {
        $tempType = request()->is_pc ? 'pc_home' : 'mobile_home';
        $temp     = $this->where('template_type', $tempType)->findOrEmpty();
        if ($temp->isEmpty() || !count($temp->template_data)) return request()->mhm_id == 1 ? [] : $this->getDefaultTemplate();
        $data = [];
        $k    = 0;
        foreach ($temp->template_data as $item) {
            $data[$k]['key']   = $item['component'];
            $form              = $item['setStyle']['form'];
            $data[$k]['title'] = $form['title'] ?? $item['setStyle']['title'];
            $sourceType        = $form['source'] ?? '';
            $sourceList        = $form['source_list'] ?? [];
            $number            = $form['number'] ?? 0;
            $arrange           = $form['arrange_type'] ?? 0;
            $column            = $form['column'] ?? 0;
            $arrange && $data[$k]['arrange'] = $arrange;
            $ids = array_column($sourceList, 'value');
            switch ($item['component']) {
                case 'navigation':
                case 'topNav':
                    $number && $data[$k]['number'] = $number;
                    $data[$k]['list'] = $sourceList;
                    break;
                case 'graphicNav':
                case 'banner':
                case 'advert':
                    // 处理图片地址
                    foreach ($sourceList as &$sourceItem) {
                        if (isset($sourceItem['icon_id']) && $sourceItem['icon_id']) {
                            $sourceItem['url'] = app(Attach::class)->where('id', $sourceItem['icon_id'])->findOrEmpty()->fileurl;
                        }
                    }
                    unset($sourceItem);
                    $number && $data[$k]['number'] = $number;
                    $data[$k]['list'] = $sourceList;
                    break;
                case 'intentCourse':
                    $data[$k]['column']         = $column;
                    $data[$k]['number']         = $number;
                    $data[$k]['category_title'] = $this->getFavoriteTitle();
                    $data[$k]['list']           = $this->getFavoriteCourse($number);
                    break;
                case 'course':
                    $data[$k]['source'] = $sourceType;
                    $courseType         = $item['setStyle']['form']['course_type'];
                    $column && $data[$k]['column'] = $column;
                    $customIds        = $sourceType == 'custom' ? $ids : [];
                    $data[$k]['list'] = $this->getTemplateCourse($courseType, $sourceType, $number, $customIds);
                    break;
                case 'teacher':
                    $column && $data[$k]['column'] = $column;
                    $data[$k]['list'] = $this->getTemplateTeacher($sourceType, $number, $ids);
                    break;
                case 'topic':
                    $column && $data[$k]['column'] = $column;
                    $data[$k]['list'] = $this->getTemplateTopic($sourceType, $number, $ids);
                    break;
                case 'featured':
                    if ($sourceType) {
                        // 全部分类，循环一级
                        $top = app(Category::class)->getTopCategory(0, [['mhm_id', '=', request()->mhm_id]]);
                        foreach ($top as $cate) {
                            $data[$k]['key']    = $item['component'];
                            $data[$k]['title']  = $cate['title'];
                            $cate               = [
                                'label'    => $cate['title'],
                                'value'    => $cate['id'],
                                'children' => app(Category::class)->where('pid', $cate['id'])->field('id as value,title as label')->order('sort')->select()->toArray()
                            ];
                            $data[$k]['cate']   = $cate;
                            $data[$k]['list']   = count($cate['children']) ? $this->getCategoryCourse($cate['children'][0]['value']) : [];
                            $data[$k]['advert'] = $this->getCategoryCourseAdvert([['category', 'like', '%,' . $cate['value'] . ',%']]);
                            $k++;
                        }
                    } else {
                        $cate               = empty($sourceList) ? ['label' => '', 'children' => []] : $this->getCategoryFirst2Level($sourceList[0]);
                        $data[$k]['key']    = $item['component'];
                        $data[$k]['title']  = $cate['label'];
                        $data[$k]['cate']   = $cate;
                        $data[$k]['list']   = count($cate['children']) ? $this->getCategoryCourse($cate['children'][0]['value']) : [];
                        $data[$k]['advert'] = $this->getCategoryCourseAdvert([['id', '=', $form['advert_course_id']]]);
                    }
                    break;
            }
            $k++;
        }
        return array_values($data);
    }

    /**
     * getTemplateCourse
     * Author: 亓官雨树 <lucky.max@foxmail.com>
     * Date: 23/07/07
     *
     * @param       $courseType
     * @param       $sourceType
     * @param       $number
     * @param array $customIds
     * @param int   $cate
     * @return Course[]|array|Collection
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    private function getTemplateCourse($courseType, $sourceType, $number, array $customIds = [], int $cate = 0)
    {
        // field
        $field = '__TABLE__.id,__TABLE__.title,__TABLE__.course_type,__TABLE__.cover,__TABLE__.price,edu_course.teacher_id,scribing_price,sale_count,sale_count_market';
        // builder
        $builder = app(Course::class)->where('__TABLE__.status', 1)->scope('listingTime,solo,expire');
        // 课程类型
        if ($courseType) $builder = $builder->where('__TABLE__.course_type', $courseType);
        // 分类
        $raw = (1 == request()->mhm_id) ? 'category IS NOT NULL AND category <> ""' : 'mhm_id=' . request()->mhm_id;
        // 讲师信息
        $builder = $builder->whereRaw($raw)->with(['teacher_name', 'teacher_avatar']);
        // 来源
        switch ($sourceType) {
            case 'latest': // 最新课程
                $builder = $builder->order('create_time', 'DESC')->limit($number);
                break;
            case 'hot': // 热销课程
                // if (!$courseType) $courseType = '1,2,3,4';
                // $ids     = app(PaymentOrderItem::class)->getWellSaleCourseIds(strval($courseType), $number);
                // $ids_str = implode(',', $ids);
                // $builder = $builder->whereIn('id', $ids_str)->orderRaw("FIND_IN_SET(id,'$ids_str')");
                $builder = $builder->order(['sale_count' => 'DESC', 'score_average' => 'DESC'])->limit($number);
                break;
            case 'splendid': // 推荐课程
                $builder = $builder->where('is_recommend', 1)->order(['best_sort', 'update_time' => 'DESC'])->limit($number);
                break;
            case 'event': // 活动课程
                $time    = time();
                $ids     = app(Promotion::class)->where('status', 1)->where('start_time', '<', $time)->where('end_time', '>', $time)->limit($number)->column('product_id');
                $builder = $builder->where('id', 'IN', $ids);
                break;
            case 'free': // 免费课程
                $builder = $builder->where('price', '<=', '0')->limit($number);
                break;
            case 'lately_live': // 最近直播
                $ids     = app(CourseSection::class)->where('start_time', '>', strtotime('today'))->where('end_time', '>', time())->group('course_id')->order('start_time')->column('id');
                $ids_str = implode(',', $ids);
                $field   .= ',sec.start_time,sec.end_time,sec.id as sec_id';
                $builder = $builder->whereIn('sec.id', $ids_str)->orderRaw("FIND_IN_SET(edu_course.id,'$ids_str')")->join('course_section sec', 'edu_course.id=sec.course_id')->limit($number);
                break;
            case 'custom':
                $ids_str = implode(',', $customIds);
                $builder->whereIn('edu_course.id', $ids_str);
                break;
        }
        $cate && $builder = $builder->where('category', 'like', '%,' . $cate . ',%');
        $data = $builder->field($field)->select();
        return $this->courseAppend($data, $sourceType == 'splendid');
    }

    /**
     * getTemplateTeacher
     * Author: 亓官雨树 <lucky.max@foxmail.com>
     * Date: 23/07/10
     *
     * @param $sourceType
     * @param $number
     * @param $ids
     * @return mixed
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    private function getTemplateTeacher($sourceType, $number, $ids)
    {
        $map = [];
        if (!$sourceType) {
            $map[] = ['id', 'IN', $ids];
        } else if (!request()->is_platform) {
            $map[] = ['mhm_id', '=', request()->mhm_id];
        }

        return app(Teacher::class)->with(['teacher_avatar', 'teacher_name', 'level_text', 'signature'])->field('id,level_id,user_id')->where('status', 1)->whereNull('delete_time')->where($map)->order(['best_sort' => 'asc', 'update_time' => 'DESC'])->limit($number)->select();
    }

    /**
     * getTemplateTopic
     * Author: 亓官雨树 <lucky.max@foxmail.com>
     * Date: 23/07/10
     *
     * @param $sourceType
     * @param $number
     * @param $ids
     * @return Topic[]|array|Collection
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    private function getTemplateTopic($sourceType, $number, $ids)
    {
        $map = [];
        if (!$sourceType) {
            $map[] = ['id', 'IN', $ids];
        } else if (!request()->is_platform) {
            $map[] = ['mhm_id', '=', request()->mhm_id];
        }

        return app(Topic::class)->field('id,title,abstract,cover,publish_time,read_count')->with(['cover_url'])->limit($number)->order(['best_sort' => 'asc', 'update_time' => 'DESC'])->where($map)->select();
    }

    /**
     * getCategoryCourse
     * Author: 亓官雨树 <lucky.max@foxmail.com>
     * Date: 23/07/10
     *
     * @param      $category
     * @return Course[]|array|Collection
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    private function getCategoryCourse($category)
    {
        $scope     = ['status', 'listingTime', 'solo', 'expire'];
        $field     = 'id,title,course_type,price,cover,sale_count,sale_count_market';
        $cateField = request()->mhm_id == 1 ? 'category' : 'mhm_category';
        $data      = app(Course::class)->scope($scope)->field($field)->whereLike($cateField, '%,' . $category . ',%')->limit(8)->select();
        return $this->courseAppend($data);
    }

    /**
     * 课程数据append信息
     * Author: 亓官雨树 <lucky.max@foxmail.com>
     * Date: 23/07/11
     *
     * @param      $course
     * @param bool $splendid
     * @return mixed
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public function courseAppend($course, $splendid = false)
    {
        return $course->append(['course_type_text', 'user_price', 'cover_url'])->each(function ($i) use ($splendid) {
            // 当前用户是否购买
            $i->is_buy = app(CourseStudent::class)->isBuy($i->id);
            // 获取活动类型，无活动返回0
            $promotion                    = app(Promotion::class)->getProductCurrentPromotion(intval($i->course_type), intval($i->id));
            $i->promotion_type            = $promotion->type;
            $i->promotion_type_text       = $promotion->type_text;
            $i->promotion_price           = $promotion->price;
            $i->promotion_running_status  = $promotion->running_status;
            $i->promotion_start_countdown = $promotion->start_countdown;
            $i->promotion_end_countdown   = $promotion->end_countdown;
            $i->promotion_end_time        = $promotion->end_time;
            // 直播信息
            if ($i->sec_id) {
                $sec           = new ArrayObject();
                $sec->id       = $i->sec_id;
                $sec->end_time = $i->end_time;
                $i->live_rate  = app(CourseSection::class)->parseLiveRate($sec, false);
            } else if ($i->course_type == 2) {
                $live          = app(CourseSection::class)->where('start_time', '>', strtotime('today'))->where('end_time', '>', time())->where('course_id', $i->id)->order('start_time')->findOrEmpty();
                $i->start_time = $live->isEmpty() ? 0 : $live->start_time;
                $i->end_time   = $live->isEmpty() ? 0 : $live->end_time;
            }
            // 班级课讲师
            if ($splendid) {
                $i->teacher = $i->course_type == 4 ? $this->getClassesTeachers($i->id) : [];
            }
        })->hidden(['sale_count_market']);
    }

    /**
     * getCategoryFirst2Level
     * Author: 亓官雨树 <lucky.max@foxmail.com>
     * Date: 23/07/10
     *
     * @param $cate
     * @return mixed
     */
    private function getCategoryFirst2Level($cate)
    {
        foreach ($cate['children'] as &$child) {
            unset($child['children']);
        }
        return $cate;
    }

    /**
     * getTemplateCateData
     * Author: 亓官雨树 <lucky.max@foxmail.com>
     * Date: 23/07/11
     *
     * @param int $cate
     * @return array
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public function getTemplateCateData(int $cate): array
    {
        $pc = request()->is_pc;
        return $pc ? $this->getTemplateCateDataPc($cate) : $this->getTemplateCateDataMobile($cate);

    }

    /**
     * getTemplateCateDataPc
     * Author: 亓官雨树 <lucky.max@foxmail.com>
     * Date: 23/07/14
     *
     * @param $cate
     * @return array
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public function getTemplateCateDataPc($cate): array
    {
        return $this->getCategoryCourse($cate)->toArray();
    }

    /**
     * getTemplateCateDataMobile
     * Author: 亓官雨树 <lucky.max@foxmail.com>
     * Date: 23/07/14
     *
     * @param int $cate
     * @return array
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public function getTemplateCateDataMobile(int $cate): array
    {
        $data = [];
        // 最近直播
        $data[] = [
            'key'     => 'course',
            'source'  => 'lately_live',
            'arrange' => 1,
            'title'   => '最近直播',
            'list'    => $this->getTemplateCourse(2, 'lately_live', 3, [], $cate)
        ];
        // 推荐课程
        $data[] = [
            'key'     => 'course',
            'source'  => 'splendid',
            'arrange' => 2,
            'title'   => '推荐课程',
            'list'    => $this->getTemplateCourse(2, 'splendid', 4, [], $cate)
        ];
        // 免费课程
        $data[] = [
            'key'     => 'course',
            'source'  => 'free',
            'arrange' => 1,
            'title'   => '免费课程',
            'list'    => $this->getTemplateCourse(2, 'free', 3, [], $cate)
        ];
        return $data;
    }

    /**
     * getTemplateCateDataMobile
     * Author: 亓官雨树 <lucky.max@foxmail.com>
     * Date: 23/07/14
     *
     * @param int $cate
     * @return array
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public function getTemplateCateDataMobileOld(int $cate): array
    {
        $temp = $this->where('template_type', 'mobile_home')->findOrEmpty();
        if ($temp->isEmpty() || !count($temp->template_data)) return [];
        $data = [];
        $k    = 0;
        foreach ($temp->template_data as $item) {
            switch ($item['component']) {
                case 'topNav':
                case 'graphicNav':
                case 'banner':
                case 'advert':
                    $data[$k]['key']     = $item['component'];
                    $data[$k]['type']    = $item['type'] ?? '';
                    $data[$k]['title']   = $item['setStyle']['form']['title'] ?? $item['setStyle']['title'];
                    $data[$k]['list']    = $item['setStyle']['form']['source_list'] ?? [];
                    $data[$k]['arrange'] = $item['setStyle']['form']['arrange_type'] ?? 0;
                    $k++;
                    break;
            }
        }

        $data[$k] = [
            'key'   => 'featured',
            'title' => app(Category::class)->where('id', $cate)->value('title'),
            'list'  => $this->getCategoryCourse($cate)
        ];
        return $data;
    }

    /**
     * @throws ModelNotFoundException
     * @throws DataNotFoundException
     * @throws DbException
     */
    private function getClassesTeachers($id)
    {
        return app(Classes::class)->getClassesTeachers($id);
    }

    /**
     * 分类课程广告位数据
     * Author: 亓官雨树 <lucky.max@foxmail.com>
     * Date: 23/07/26
     *
     * @param $map
     * @return Course|array|Model
     */
    private function getCategoryCourseAdvert($map)
    {
        return app(Course::class)->field('id,title,cover,price,course_type,sale_count,sale_count_market')->with(['cover_url'])->where($map)->order(['is_recommend' => 'DESC', 'best_sort', 'update_time' => 'DESC'])->findOrEmpty()->hidden(['cover', 'sale_count_market']);
    }

    /**
     * getFavoriteTitle
     * Author: 亓官雨树 <lucky.max@foxmail.com>
     * Date: 23/09/21
     *
     * @return mixed|object|string|App
     */
    public function getFavoriteTitle()
    {
        return app(Course::class)->getFavoriteTitle();
    }

    /**
     * getFavoriteCourse
     * Author: 亓官雨树 <lucky.max@foxmail.com>
     * Date: 23/09/07
     *
     * @param $limit
     * @return array|mixed|object|App
     */
    public function getFavoriteCourse($limit)
    {
        return app(Course::class)->getFavoriteCourse($limit);
    }

    /**
     * getDefaultTemplate
     * Author: 亓官雨树 <lucky.max@foxmail.com>
     * Date: 23/10/31
     */
    public function getDefaultTemplate()
    {
        $tempType = request()->is_pc ? 'pc_home' : 'mobile_home';
        $temp     = $this->withoutGlobalScope()->where('template_type', $tempType)->where('mhm_id', 0)->findOrEmpty();
        $data     = [];
        $k        = 0;
        if (empty($temp->template_data)) return $data;
        foreach ($temp->template_data as $item) {
            $data[$k]['key']   = $item['component'];
            $form              = $item['setStyle']['form'];
            $data[$k]['title'] = $form['title'] ?? $item['setStyle']['title'];
            $sourceType        = $form['source'] ?? '';
            $sourceList        = $form['source_list'] ?? [];
            $number            = $form['number'] ?? 0;
            $arrange           = $form['arrange_type'] ?? 0;
            $column            = $form['column'] ?? 0;
            $arrange && $data[$k]['arrange'] = $arrange;
            switch ($item['component']) {
                case 'navigation':
                case 'topNav':
                    $number && $data[$k]['number'] = $number;
                    $data[$k]['list'] = $sourceList;
                    break;
                case 'graphicNav':
                case 'banner':
                case 'advert':// 处理图片地址
                    foreach ($sourceList as &$sourceItem) {
                        if (isset($sourceItem['icon_id']) && $sourceItem['icon_id']) {
                            $sourceItem['url'] = app(Attach::class)->where('id', $sourceItem['icon_id'])->findOrEmpty()->fileurl;
                        }
                    }
                    unset($sourceItem);
                    $number && $data[$k]['number'] = $number;
                    $data[$k]['list'] = $sourceList;
                    break;
                case 'intentCourse':
                    $data[$k]['column']         = $column;
                    $data[$k]['number']         = $number;
                    $data[$k]['category_title'] = '意向课程';
                    $data[$k]['list']           = $this->getDefaultFavoriteCourse();
                    break;
                case 'course':
                    $data[$k]['source'] = $sourceType;
                    $column && $data[$k]['column'] = $column;
                    $data[$k]['list'] = $this->getDefaultTemplateCourse();
                    break;
                case 'teacher':
                    $column && $data[$k]['column'] = $column;
                    $data[$k]['list'] = $this->getDefaultTemplateTeacher();
                    break;
                case 'topic':
                    $column && $data[$k]['column'] = $column;
                    $data[$k]['list'] = $this->getDefaultTemplateTopic();
                    break;
                case 'featured':
                    $data[$k]['key']    = $item['component'];
                    $data[$k]['title']  = '分类课程展示';
                    $data[$k]['cate']   = $this->getDefaultTemplateCate();
                    $data[$k]['list']   = $this->getDefaultTemplateCourse();
                    $data[$k]['advert'] = $this->getDefaultCategoryCourseAdvert();
                    break;
            }
            $k++;
        }
        return array_values($data);
    }

    /**
     * 虚拟意向课程
     * Author: 亓官雨树 <lucky.max@foxmail.com>
     * Date: 23/10/31
     *
     * @return array[]
     */
    private function getDefaultFavoriteCourse()
    {
        return [
            [
                'course_type'       => 2,
                'course_type_text'  => "直播",
                'cover_url'         => "",
                'id'                => 0,
                'price'             => 99,
                'sale_count'        => 99,
                'sale_count_market' => 199,
                'status'            => 1,
                'title'             => "直播课展示",
                'user_price'        => 99,
            ]
        ];
    }

    /**
     * 虚拟课程数据
     * Author: 亓官雨树 <lucky.max@foxmail.com>
     * Date: 23/10/31
     *
     * @return array[]
     */
    private function getDefaultTemplateCourse()
    {
        return [
            [
                'course_type'               => 1,
                'course_type_text'          => "点播",
                'cover'                     => 0,
                'cover_url'                 => "",
                'id'                        => 0,
                'is_buy'                    => 0,
                'price'                     => 69,
                'promotion_end_countdown'   => 0,
                'promotion_end_time'        => null,
                'promotion_price'           => null,
                'promotion_running_status'  => 0,
                'promotion_start_countdown' => 0,
                'promotion_type'            => null,
                'promotion_type_text'       => "",
                'sale_count'                => 1,
                'scribing_price'            => 99,
                'teacher_avatar'            => null,
                'teacher'                   => [
                    'avatar'  => "",
                    'id'      => 0,
                    'title'   => "讲师展示",
                    'user_id' => 0,
                ],
                'teacher_id'                => 0,
                'teacher_name'              => "讲师展示",
                'title'                     => "课程展示",
                'user_price'                => 69
            ]
        ];
    }

    /**
     * 虚拟讲师数据
     * Author: 亓官雨树 <lucky.max@foxmail.com>
     * Date: 23/10/31
     *
     * @return array[]
     */
    private function getDefaultTemplateTeacher()
    {
        return [
            [
                'avatar'     => null,
                'id'         => 0,
                'level_id'   => 2,
                'level_text' => "中级",
                'signature'  => "这个人很懒，什么都没有留下！",
                'title'      => "讲师展示",
                'user_id'    => 0
            ]
        ];
    }

    /**
     * 虚拟资讯数据
     * Author: 亓官雨树 <lucky.max@foxmail.com>
     * Date: 23/10/31
     *
     * @return array[]
     */
    private function getDefaultTemplateTopic()
    {
        return [[
            'abstract'     => "资讯简介",
            'cover'        => 0,
            'cover_url'    => "",
            'id'           => 0,
            'publish_time' => 1692344823,
            'read_count'   => 94,
            'title'        => "资讯展示",
        ]];
    }

    /**
     * 虚拟分类数据
     * Author: 亓官雨树 <lucky.max@foxmail.com>
     * Date: 23/10/31
     *
     * @return array
     */
    private function getDefaultTemplateCate()
    {
        return [
            'value'    => 0,
            'label'    => '分类课程展示',
            'disabled' => false,
            'children' => [
                [
                    'value'    => 0,
                    'label'    => '分类课程二级展示',
                    'disabled' => false,
                ]
            ],
        ];
    }

    /**
     * 虚拟分类课程广告位展示
     * Author: 亓官雨树 <lucky.max@foxmail.com>
     * Date: 23/10/31
     *
     * @return array
     */
    private function getDefaultCategoryCourseAdvert()
    {
        return [
            'course_type' => 1,
            'cover_url'   => "",
            'id'          => 0,
            'price'       => 0,
            'sale_count'  => 11,
            'title'       => "分类课程展示",
            'user_price'  => 0,
        ];
    }
}
